package com.rtsapp.server.domain.mysql.sql;

import com.rtsapp.server.domain.mysql.sql.impl.DatabaseWorkerPoolImpl;
import com.rtsapp.server.module.AbstractModule;
import com.rtsapp.server.module.Application;
import com.rtsapp.server.module.Module;
import com.rtsapp.server.logger.Logger;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;


public class MySQLModule extends AbstractModule {

    private static final Logger LOGGER =com.rtsapp.server.logger.LoggerFactory.getLogger(MySQLModule.class);
    private static final int MAX_QUEUE_SIZE = 2 << 20;//1048576
    //连接信息
    private final Map<String, MySQLConnectionInfo> connectInfos = new HashMap<>();
    //应用程序
    private Application application;
    private String hbm2ddl = "update";
    //用于进行hbm2ddl的处理
    private String hibernateCfgFile = "cfg/hibernate.cfg.xml";
    //工作池
    private Map<String, DatabaseWorkerPool> dbPools = new HashMap<>();

    public void setHbm2ddl(String hbm2ddl) {
        this.hbm2ddl = hbm2ddl;
    }

    public void setConnectionInfo(Map<String, MySQLConnectionInfo> connectionInfo) {
        connectInfos.putAll(connectionInfo);
    }

    public void setHibernateCfgFile(String hibernateCfgFile) {
        this.hibernateCfgFile = hibernateCfgFile;
    }


    @Override
    public boolean initialize(Module parentModule) {
        this.application = (Application) parentModule;
        return true;
    }

    @Override
    public boolean start() {

        hbm2ddl(hibernateCfgFile);

        if (!openDBWorkerPool()) {
            return false;
        }

        if (!createDao()) {
            return false;
        }

        return true;
    }

    @Override
    public void stop() {
        Set<DatabaseWorkerPool> pools = new HashSet<>();
        pools.addAll(dbPools.values());

        for (DatabaseWorkerPool pool : pools) {
            pool.close();
        }
    }

    @Override
    public void destroy() {

    }


    public DatabaseWorkerPool getWorkPool(String key) {
        DatabaseWorkerPool workerPool = this.dbPools.get(key.trim());
        if (workerPool == null) {
            LOGGER.error("worker " + key + " is null");
        }
        return workerPool;
    }

    /**
     * ping连接
     */
    public void dbPoolKeepAlive() {
        try {
            Set<DatabaseWorkerPool> uniquePool = new HashSet<>();
            uniquePool.addAll(this.dbPools.values());

            for (DatabaseWorkerPool pool : uniquePool) {
                if (pool != null) {
                    pool.keepAlive();
                }
            }
        } catch (Throwable ex) {
            LOGGER.error("dbPoolKeepAlive error", ex);
        }
    }

    /**
     * 创建dao, 这个方法将在下一版本移除
     * 不使用继承的方式，而使用组合的方式来使用MySQLModule
     *
     * @return
     */
    @Deprecated
    protected boolean createDao() {
        return true;
    }


    private boolean openDBWorkerPool() {

        for (String keyStr : connectInfos.keySet()) {

            MySQLConnectionInfo connInfo = connectInfos.get(keyStr);

            DatabaseWorkerPool pool = new DatabaseWorkerPoolImpl(MAX_QUEUE_SIZE, connInfo );
            if (!pool.open()) {
                return false;
            }

            String[] keys = keyStr.split(",");
            for (String key : keys) {
                dbPools.put(key.trim(), pool);
            }
        }

        return true;
    }

    private void hbm2ddl(String file) {

        Configuration config = new Configuration();
        File hibernateCfgFile = new File(file);

        if (!hibernateCfgFile.exists()) {
            LOGGER.error("服务器配置文件不存在:" + hibernateCfgFile.getPath());
            throw new HibernateException("服务器配置文件不存在");
        }
        config.configure(hibernateCfgFile);


        Set<MySQLConnectionInfo> connectionSets = new HashSet<MySQLConnectionInfo>();
        connectionSets.addAll(this.connectInfos.values());

        for (MySQLConnectionInfo connInfo : connectionSets) {

            config.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
            config.setProperty("hibernate.connection.driver_class", "com.mysql.jdbc.Driver");
            config.setProperty("hibernate.connection.url", connInfo.getJDBCURL());
            config.setProperty("hibernate.connection.username", connInfo.getUser());
            config.setProperty("hibernate.connection.password", connInfo.getPassword());

            if (hbm2ddl.equals("create")) {
                config.setProperty("hibernate.hbm2ddl.auto", "create");
            } else {
                config.setProperty("hibernate.hbm2ddl.auto", "update");
            }
            config.setProperty("hibernate.show_sql", "true");
            config.setProperty("hibernate.format_sql", "true");


            ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
                    .applySettings(config.getProperties()).build();
            SessionFactory sessionFactory = config.buildSessionFactory(serviceRegistry);

            sessionFactory.close();

        }

        LOGGER.debug("hbm2ddl 成功");
    }


}
